package com.leyou.order.service;

import com.leyou.common.auth.pojo.UserHolder;
import com.leyou.common.constant.LyConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Sku;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.dto.OrderStatusEnum;
import com.leyou.order.dto.OrderVO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;

    public Long saveOrder(OrderDTO orderDTO) {
        try {
            //保存订单表
            //生成订单号
            Long orderId = idWorker.nextId();
            //创建订单对象
            Order order = new Order();
            order.setOrderId(orderId);
            order.setStatus(OrderStatusEnum.INIT.value());
            order.setPostFee(0L);
            order.setPaymentType(orderDTO.getPaymentType());
            order.setInvoiceType(0);
            order.setUserId(UserHolder.getUserId());
            order.setSourceType(2);
            //获取所有购买的购物车
            List<CartDTO> carts = orderDTO.getCarts();
            //使用流将购物车集合转成map
            Map<Long, Integer> cartMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //获取所有购物车的id集合，也就是所有购买的sku的id集合
            List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            //根据sku的id集合查询sku对象集合
            List<Sku> skus = itemClient.findSkusByIds(skuIds);
            //计算总金额
            long totalFee = skus.stream().mapToLong(sku -> sku.getPrice() * cartMap.get(sku.getId())).sum();
            order.setTotalFee(totalFee);
            order.setActualFee(1L);
            //保存数据库
            orderMapper.insertSelective(order);

            //保存订单详情表
            //创建订单详情列表对象
            List<OrderDetail> orderDetails = new ArrayList<>();
            //遍历sku集合给orderDetails赋值
            skus.forEach(sku -> {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setId(idWorker.nextId());
                orderDetail.setOrderId(orderId);
                orderDetail.setSkuId(sku.getId());
                orderDetail.setTitle(sku.getTitle());
                orderDetail.setOwnSpec(sku.getOwnSpec());
                orderDetail.setPrice(sku.getPrice());
                orderDetail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
                orderDetail.setNum(cartMap.get(sku.getId()));
                orderDetail.setCreateTime(new Date());
                orderDetail.setUpdateTime(new Date());
                orderDetails.add(orderDetail);
            });
            //批量保存订单详情
            orderDetailMapper.insertList(orderDetails);

            //保存订单物流信息
            //获取用户的物流信息
            AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUserId(), orderDTO.getAddressId());
            //将AddressDTO对象转成物流对象
            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
            //给物流信息赋值订单号
            orderLogistics.setOrderId(orderId);
            //保存物流信息
            orderLogisticsMapper.insertSelective(orderLogistics);

            //减库存
            itemClient.minusStock(cartMap);
            //删除购物车【思考：下单删还是支付删？自己想，课堂不讲。】
            return orderId;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    public OrderVO findOrderById(Long id) {
        try {
            //根据订单id查询订单对象
            Order order = orderMapper.selectByPrimaryKey(id);
            //将Order转成OrderVO
            OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);

            //根据订单id查询订单详情列表
            OrderDetail record = new OrderDetail();
            record.setOrderId(orderVO.getOrderId());
            List<OrderDetail> orderDetails = orderDetailMapper.select(record);
            //把订单详情列表放入OrderVO
            orderVO.setDetailList(orderDetails);

            //根据订单id查询订单物流信息
            OrderLogistics orderLogistics = orderLogisticsMapper.selectByPrimaryKey(order.getOrderId());
            //把订单物流信息放入OrderVO
            orderVO.setLogistics(orderLogistics);
            return orderVO;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }

    }

    public String getPayUrl(Long id) {
        //得到当前订单在redis中存储支付链接的key
        String key = LyConstants.PAY_URL_KEY_PRE+id;
        //从redis中获取支付链接
        if(redisTemplate.hasKey(key)){
            return redisTemplate.opsForValue().get(key);
        }
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        //判断当前订单是否已经支付
        if(order.getStatus() != OrderStatusEnum.INIT.value()){
            throw new LyException(501, "订单已支付");
        }
        //获取支付链接
        String codeUrl = payHelper.getCodeUrl(id, order.getActualFee());
        //把codeUrl放入redis
        redisTemplate.opsForValue().set(key, codeUrl, 2, TimeUnit.HOURS);
        return codeUrl;
    }

    public Integer findOrderStatus(Long id) {
        Order order = orderMapper.selectByPrimaryKey(id);
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }

    public void getWxNotify(Map<String, String> notifyParam) {
        //验证微信通知的通信标识和交易标识
        payHelper.checkResp(notifyParam);
        //获取商户订单号
        Long outTradeNo = Long.valueOf(notifyParam.get("out_trade_no"));
        //获取支付金额
        String totalFee = notifyParam.get("total_fee");
        Long totalFeeL = Long.valueOf(totalFee);
        //根据订单号查询订单
        Order order = orderMapper.selectByPrimaryKey(outTradeNo);
        if(order==null){
            log.error("【微信支付结果通知】找不到对应订单！");
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        if(order.getStatus()!=OrderStatusEnum.INIT.value()){
            log.error("【微信支付结果通知】订单已经支付过了！");
            throw new LyException(501, "订单已支付，请不要重复支付！");
        }
        //比对金额
        if(!totalFeeL.equals(order.getActualFee())){
            log.error("【微信支付结果通知】支付金额与订单应付金额不一致！");
            throw new LyException(501, "支付金额与订单应付金额不一致！");
        }
        //修改订单状态
        Order record = new Order();
        record.setOrderId(outTradeNo);
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateByPrimaryKeySelective(record);
        if(count!=1){
            log.error("【微信支付结果通知】更新订单状态失败！");
        }
    }
}